﻿namespace FsharpCad


#if zcad

open ZwSoft.ZwCAD.DatabaseServices
open ZwSoft.ZwCAD.EditorInput
open ZwSoft.ZwCAD.Geometry
open ZwSoft.ZwCAD.Runtime
/// cad Application 对象
type AcCoreApp = ZwSoft.ZwCAD.ApplicationServices.Core.Application
/// cad 异常对象
type AcExn = Exception
#endif
#if acad
open Autodesk.AutoCAD.DatabaseServices
open Autodesk.AutoCAD.EditorInput
open Autodesk.AutoCAD.Geometry
open Autodesk.AutoCAD.Runtime
/// cad Application 对象
type AcCoreApp = Autodesk.AutoCAD.ApplicationServices.Core.Application
/// cad 异常对象
type AcExn = Exception
#endif
open System.Collections.Generic
open FSharp.Collections
open Microsoft.FSharp.Collections

/// 获取计算表达式
type PromptBuilder() =
    member _.Bind(v: #PromptResult, f) =
        if v.Status = PromptStatus.OK || v.Status = PromptStatus.Keyword then f v else None

    member _.Return(v) = Some v
    member _.Zero() = None

/// hahahah

/// 基础函数模块
module Library =
    
        /// <summary>
    /// 获取点
    /// </summary>
    /// <param name="pt">基点</param>
    /// <param name="msg">提示</param>
    /// <returns>PromptPointResult</returns>
    let getPoint (pt, msg: string) =
        let opt = PromptPointOptions(msg, UseBasePoint = true, BasePoint = pt)
        AcCoreApp.DocumentManager.MdiActiveDocument.Editor.GetPoint(opt)
    
    /// <summary>
    /// 获取点
    /// </summary>
    /// <param name="msg">提示</param>
    /// <returns>PromptPointResult</returns>
    let getPointMsg (msg: string) =
        AcCoreApp.DocumentManager.MdiActiveDocument.Editor.GetPoint(msg)
    
    /// <summary>
    /// 获取距离
    /// </summary>
    /// <param name="pt">基点</param>
    /// <param name="msg">提示</param>
    /// <returns>PromptDoubleResult</returns>
    let getDist (pt, msg) =
        AcCoreApp.DocumentManager.MdiActiveDocument.Editor
            .GetDistance(PromptDistanceOptions(msg, UseBasePoint = true, BasePoint = pt))
    
    /// <summary>
    /// 命令行输出
    /// </summary>
    /// <param name="x">要输出的内容</param>
    let print x = AcCoreApp.DocumentManager.MdiActiveDocument.Editor
                      .WriteMessage($"{x}\n")
    
    
    
    /// 获取计算表达式对象
    let prompt = PromptBuilder()
    
    /// <summary>
    /// 获取顶层事务
    /// </summary>
    /// <param name="db">数据库</param>
    let getTopTransaction (db: Database) =
        match db.TransactionManager.TopTransaction with
        | null -> raise (AcExn(ErrorStatus.NoActiveTransactions))
        | tr -> tr
    
    /// <summary>
    /// 获取对象
    /// </summary>
    /// <param name="mode">打开模式</param>
    /// <param name="id">对象id</param>
    /// <returns>获取的对象</returns>
    let inline getObject<'T when 'T :> DBObject> mode (id: ObjectId) =
        let tr = getTopTransaction id.Database
        tr.GetObject(id, mode) :?> 'T
    
    /// <summary>
    /// 批量获取对象
    /// </summary>
    /// <param name="mode">打开模式</param>
    /// <param name="ids">对象id集合</param>
    /// <returns>对象集合</returns>
    let inline getObjects<'T when 'T :> DBObject> mode (ids: System.Collections.IEnumerable) =
        let rx = RXObject.GetClass typeof<'T>

        ids
        |> Seq.cast<ObjectId>
        |> Seq.choose (fun id ->
            if id.ObjectClass.IsDerivedFrom rx then
                Some(getObject<'T> mode id)
            else
                None)
    
    /// <summary>
    /// 写模式打开对象
    /// </summary>
    /// <param name="action">打开对象后进行的操作lambda</param>
    /// <param name="obj">对象</param>
    /// <returns>对象</returns>
    let inline forWrite action (obj: #DBObject) =
        let _isWriteEnabled = obj.IsWriteEnabled

        if not _isWriteEnabled then
            obj.UpgradeOpen()

        action obj

        if not _isWriteEnabled then
            obj.DowngradeOpen()
    
    /// <summary>
    /// 向块表记录添加图元
    /// </summary>
    /// <param name="btr">块表记录</param>
    /// <param name="ent">图元</param>
    /// <returns>图元id</returns>
    let inline addEntity (btr: BlockTableRecord) (ent: #Entity) =
        let tr = getTopTransaction btr.Database
        let mutable id = ObjectId.Null
        btr
        |> forWrite (fun o ->
            id <- o.AppendEntity(ent)
            tr.AddNewlyCreatedDBObject(ent, true)
            )
        id
    
    /// <summary>
    /// 批量向块表记录添加图元
    /// </summary>
    /// <param name="btr">块表记录</param>
    /// <param name="entities">图元集合</param>
    /// <returns>图元id集合</returns>
    let inline addEntities (btr: BlockTableRecord) (entities: seq<#Entity>) =
        let tr = getTopTransaction btr.Database
        let ids = List<ObjectId>()
        btr
        |> forWrite (fun o ->
            entities
            |> Seq.iter (fun ent ->
                let id = o.AppendEntity(ent)
                tr.AddNewlyCreatedDBObject(ent, true)
                ids.Add(id))
            )
        ids
    
    /// <summary>
    /// 弧度转向量
    /// </summary>
    /// <param name="rad">弧度</param>
    /// <returns>向量</returns>
    let inline rad_to_vector3d rad = Vector3d(cos rad, sin rad, 0)
    
    /// <summary>
    /// 正则匹配活动模式
    /// </summary>
    /// <param name="pattern">匹配规则</param>
    /// <param name="input">原始字符串</param>
    /// <returns>匹配组option</returns>
    let (|RegMatch|_|) pattern input =
        let m = System.Text.RegularExpressions.Regex.Match(input, pattern)
        if m.Success then Some m.Groups else None
        
    /// <summary>
    /// 自定义添加事件处理函数的操作符
    /// </summary>
    /// <param name="i">事件</param>
    /// <param name="h">事件handler</param>
    let inline (+=) (i:  'T when 'T : (member AddHandler : 'Delegate -> unit )) (h: 'Delegate) =
        i.AddHandler h
    
    /// <summary>
    /// 自定义删除事件处理函数的操作符
    /// </summary>
    /// <param name="i">事件</param>
    /// <param name="h">事件handler</param>
    let inline (-=) (i:  'T when 'T : (member RemoveHandler : 'Delegate -> unit )) (h: 'Delegate) =
        i.RemoveHandler h
